home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 3 / BBS in a box - Trilogy III.iso / Files / Prog / B-C / C++Source Code Fmtr Folder / Tests / UMemory.cp < prev    next >
Encoding:
Text File  |  1991-01-07  |  41.3 KB  |  1,714 lines  |  [TEXT/MPS ]

  1. /*$P*/
  2. /*[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]*/
  3. /* UMemory.inc1.p */
  4. /* Copyright © 1985-1990 by Apple Computer, Inc.  All rights reserved. */
  5. #ifndef __UMEMEORY__
  6. #include "UMemory.h"
  7. #endif
  8.  
  9. #ifndef __UFAILURE__
  10. #include "UFailure.h"
  11. #endif
  12.  
  13. #ifndef __MEMORY__
  14. #include "Memory.h"
  15. #endif
  16.  
  17. #ifndef __TEXTEDIT__
  18. #include "Textedit.h"
  19. #endif
  20.  
  21. #ifndef __OSUTILS__
  22. #include "OSUtils.h"
  23. #endif
  24.  
  25. #ifndef __UMACAPPUTILITIES__
  26. #include "UMacAppUtilities.h"
  27. #endif
  28.  
  29. #ifndef __SYSEQU__
  30. #include "SysEqu.h"
  31. #endif
  32.  
  33. #ifndef __TRAPS__
  34. #include "Traps.h"
  35. #endif
  36.  
  37. #ifndef __DEVICES__
  38. #include "Devices.h"
  39. #endif
  40.  
  41. #ifndef __ULOMEM__
  42. #include "ULoMem.h"
  43. #endif
  44.  
  45. #ifndef __TOOLUTILS__
  46. #include "ToolUtils.h"
  47. #endif
  48.  
  49. #ifndef __RESOURCES__
  50. #include "Resources.h"
  51. #endif
  52.  
  53. #ifndef __PACKAGES__
  54. #include "Packages.h"
  55. #endif
  56.  
  57. #ifndef __ERRORS__
  58. #include "Errors.h"
  59. #endif
  60.  
  61. #ifndef __UDEBUG__
  62. #include "UDebug.h"
  63. #endif
  64.  
  65. #ifndef __SEGLOAD__
  66. #include "SegLoad.h"
  67. #endif
  68.  
  69. #if !qDebugTheDebugger
  70. #pragma W+
  71. #pragma R-
  72. #pragma Init-
  73. #pragma OV-
  74. #endif
  75.  
  76. // Globals to this module and externally available.
  77. extern Size gMaxLockedRsrc;
  78. #if qDebug
  79. extern Boolean gMemMgtBreak = false;
  80. extern Boolean gRsrcReport = false;
  81. extern Boolean gSegReport = false;
  82. #endif
  83.  
  84. HandleListHandle gSysMemList;
  85. HandleListHandle gApp1MemList;
  86. HandleListHandle gApp2MemList;
  87. HandleListHandle gCodeSegs;
  88. BoolListHandle gIsLoadedSeg;
  89. BoolListHandle gIsResidentSeg;
  90. short gCodeRefNum;
  91. Boolean gUnloadAllSegs;
  92. ProcPtr gGZPurgeNotify;
  93.  
  94. // Static, globals to this module. Many of these are static by convention, but we don't
  95. // declare them as static because people may want to examine them.
  96.  
  97. static Boolean pDuringGrowZone;
  98. Size pSzCodeReserve;
  99. Boolean pReserveExists;
  100. Handle pMemReserve;
  101. Handle pCodeReserve;
  102. Boolean pOKCodeReserve;
  103. Boolean pPermAllocation;
  104. short pMaxSegNum;
  105. Size pSzMemReserve;
  106. short pOldResFile;
  107. Boolean pLoadSegCalledFromOwnApp;
  108. TrapPatch pSegLoadPatch;
  109. LongListHandle pSegSize;
  110.  
  111. // Function prototypes for some routines in this module.
  112.  
  113. pascal long GrowZoneProc (Size needed);
  114. pascal void BuildCodeReserve (Size allocLim, Boolean fromGZ);                       
  115. pascal Boolean IsHandleEligible (Handle h);
  116.  
  117. // Function prototypes for the routines in UMemory.a
  118.  
  119. pascal void ALoadMacAppSeg (void);
  120. pascal void APostLoadMacAppSeg (void);
  121.  
  122. /* LoadSeg is Patched to call ALoadMacAppSeg, which in turn calls
  123.   LoadMacAppSegment. ALoadMacAppSeg can only be referenced as a
  124.   procedure pointer, because no args are declared */
  125.  
  126. // Other function prototypes that are externally defined.
  127.  
  128. typedef pascal void (*DoToFrameType) (long, long, long, long, void*);
  129.  
  130. pascal void EachFrameDo (long calleeFrame, long ppc,
  131.                           pascal void DoToFrame (long calleeFrame,
  132.                                                  long ppc,
  133.                                                  long callerFrame,
  134.                                                  long itsFrame,
  135.                                                  void* scopeLink),
  136.                           void *scopeLink);
  137.  
  138. pascal Boolean PreloadSegment (short segNum);
  139.  
  140. pascal void CallNotify (Handle h, ProcPtr routine) = { 0x205F, 0x4E90 };    // MOVE.L (A7)+,A0; JSR (A0) 
  141.  
  142. /*--------------------------------------------------------------------------------------------------*/
  143.  
  144.     /*
  145.     These "MAFoo" functions are primarily for THINK™ Pascal compatibility (but useful in the larger
  146.     problem of multiple open resource maps in general); when running under the THINK™ environment,
  147.     CODE resources are not found in the same resource file as other application resources, so a
  148.     UseResFile call needs to be made to bring the project resource file into the search path.
  149.     "gCodeRefNum" is set up at initialization time.
  150.     !!! A much more general solution to "the resource problem" appears to be warranted.
  151.     */
  152.  
  153. /*--------------------------------------------------------------------------------------------------*/
  154. #pragma segment MAMemoryRes
  155.  
  156. pascal Handle MAGet1Resource (ResType rType, short rID)
  157. {
  158.     short oldResFile;
  159.     Handle resource;
  160.     
  161.     oldResFile = MAUseResFile (gCodeRefNum);
  162.     resource = Get1Resource (rType, rID);
  163.     MAUseResFile (oldResFile);
  164.     
  165.     return resource;
  166. }
  167.  
  168. /*--------------------------------------------------------------------------------------------------*/
  169. #pragma segment MAMemoryRes
  170.  
  171. pascal Handle MAGet1NamedResource (ResType rType, const Str255& name)
  172. {
  173.     short oldResFile;
  174.     Handle namedResource;
  175.  
  176.     oldResFile = MAUseResFile (gCodeRefNum);
  177.     namedResource = Get1NamedResource (rType, name);
  178.     MAUseResFile (oldResFile);
  179.     
  180.     return namedResource;
  181. }
  182.  
  183. /*--------------------------------------------------------------------------------------------------*/
  184. #pragma segment MAMemoryRes
  185.  
  186. pascal Handle MAGet1IndResource (ResType rType, short index)
  187. {
  188.     short oldResFile;
  189.     Handle indResource;
  190.  
  191.     oldResFile = MAUseResFile (gCodeRefNum);
  192.     indResource = Get1IndResource (rType, index);
  193.     MAUseResFile (oldResFile);
  194.     
  195.     return indResource;
  196. }
  197.  
  198. /*--------------------------------------------------------------------------------------------------*/
  199. #pragma segment MAMemoryRes
  200.  
  201. pascal short MACount1Resources (ResType rType)
  202. {
  203.     short oldResFile;
  204.     short resourceCnt;
  205.     
  206.     oldResFile = MAUseResFile (gCodeRefNum);
  207.     resourceCnt = Count1Resources (rType);
  208.     MAUseResFile (oldResFile);
  209.     
  210.     return resourceCnt;
  211. }
  212.  
  213. /*--------------------------------------------------------------------------------------------------*/
  214. #pragma segment MAMemoryRes
  215.  
  216. pascal Handle MAGetResource (ResType rType, short rID)
  217. {
  218.     Handle    h;
  219.     short    oldResFile;
  220.  
  221.     oldResFile = MAUseResFile (gCodeRefNum);
  222.     h = GetResource (rType, rID);
  223.     MAUseResFile (oldResFile);
  224.  
  225.     return HomeResFile (h) != gCodeRefNum ? NULL : h;
  226. }
  227.  
  228. /*--------------------------------------------------------------------------------------------------*/
  229. #pragma segment MAMemoryRes
  230.  
  231. pascal Handle MAGetNamedResource (ResType rType, const Str255& name)
  232. {
  233.     Handle    h;
  234.     short    oldResFile;
  235.  
  236.     oldResFile = MAUseResFile (gCodeRefNum);
  237.     h = GetNamedResource (rType, name);
  238.     MAUseResFile (oldResFile);
  239.  
  240.     return HomeResFile (h) != gCodeRefNum ? NULL : h;
  241. }
  242.  
  243. /*--------------------------------------------------------------------------------------------------*/
  244. #pragma segment MAMemoryRes
  245.  
  246. pascal Handle MAGetIndResource(ResType rType, short index)
  247. {
  248.     Handle    h;
  249.     short    oldResFile;
  250.  
  251.     oldResFile = MAUseResFile (gCodeRefNum);
  252.     h = GetIndResource (rType, index);
  253.     MAUseResFile (oldResFile);
  254.  
  255.     return HomeResFile (h) != gCodeRefNum ? NULL : h;
  256. }
  257.  
  258. /*--------------------------------------------------------------------------------------------------*/
  259. #pragma segment MAMemoryRes
  260.  
  261. pascal short MACountResources(ResType rType)
  262. {
  263.     short    oldResFile;
  264.     short    resourceCnt;
  265.  
  266.     oldResFile = MAUseResFile (gCodeRefNum);
  267.     resourceCnt = CountResources (rType);
  268.     MAUseResFile (oldResFile);
  269.     
  270.     return resourceCnt;
  271. }
  272.  
  273. /*--------------------------------------------------------------------------------------------------*/
  274. #pragma segment MAMemoryRes
  275.  
  276. pascal Handle GetSegResource (short segNum)
  277. {
  278.     return MAGet1Resource (kCode, segNum);
  279. }
  280.  
  281. /*--------------------------------------------------------------------------------------------------*/
  282. #pragma segment MAMiniInit
  283.  
  284. pascal void AddAllRsrc (ResType rType, HandleListHandle toList)
  285. {
  286.     Boolean        oldResLoad;
  287.     short        i, nResources, theID;
  288.     Handle        h;
  289.     ResType        theType;
  290.     Str255        theName;
  291.  
  292.     oldResLoad = GetResLoad ();
  293.     SetResLoad (false);
  294.  
  295.     nResources = CountResources (rType);
  296.     for (i=1; i<=nResources; i++)
  297.     {
  298.         h = GetIndResource (rType, i);
  299.         GetResInfo (h, theID, theType, theName);
  300.  
  301.         /* If there is a ROM resource for this type and ID, don't put it
  302.             on the list. */
  303.    
  304.         UseROMMap (false);
  305.         h = GetResource (rType, theID);
  306.         UseROMMap (false);
  307.         if (HomeResFile (h) != 1)
  308.             AddHandle (h, toList);
  309.     }
  310.  
  311.     SetResLoad (oldResLoad);
  312. }
  313.  
  314. /*--------------------------------------------------------------------------------------------------*/
  315. #pragma segment MAMiniInit
  316.  
  317. pascal void AddHandle(Handle h, HandleListHandle toList)
  318. {
  319.     long    offset;
  320.  
  321.     offset = Munger ((Handle) toList, 0, NULL, 0, (Ptr) &h, 4);
  322.     FailMemError ();
  323. }
  324.  
  325. /*--------------------------------------------------------------------------------------------------*/
  326. #pragma segment MAMiniInit
  327.  
  328. pascal long AddSegSizes (Handle segRsrc)
  329. {
  330.     SignedByte        savedState;
  331.     SignedBytePtr    p;
  332.     Boolean            oldResLoad;
  333.     long            total;
  334.     Handle            seg;
  335.     short            i;
  336.     Str255            s;
  337.  
  338.     savedState = LockHandleHigh (segRsrc);
  339.  
  340.     oldResLoad = GetResLoad ();
  341.     SetResLoad (false);
  342.  
  343.     p = (SignedBytePtr) *segRsrc;
  344.     i = *((IntegerPtr) p);
  345.     p += 2;
  346.  
  347.     total = 0;
  348.  
  349.     for (; i>0; i--, p+=*p+1)
  350.     {
  351.         BlockMove ((Ptr) p, (Ptr) &s, *p + 1);
  352.         seg = MAGet1NamedResource (kCode, s);
  353.         if (seg != NULL)
  354.             total += SizeResource (seg) + 8;
  355.     }
  356.     
  357.     SetResLoad (oldResLoad);
  358.     HSetState (segRsrc, savedState);
  359.     
  360.     return total;
  361. }
  362.  
  363. /*--------------------------------------------------------------------------------------------------*/
  364. #pragma segment MAMemoryRes
  365. #pragma Push
  366. #if qTrace
  367. #pragma D+
  368. #endif
  369.  
  370. pascal void BuildAllReserves ()
  371.  
  372. {
  373.     static const short initVal = 0xF7;
  374.  
  375.     Boolean    oldPerm;
  376. #if qDebug
  377.     Size    theSize;
  378. #endif
  379.     
  380.     /* set the permanent flag to ensure that the code reserve is
  381.     actually allocated and not given up to the low space reserve */
  382.     
  383.     oldPerm = pPermAllocation;
  384.     pPermAllocation = true;
  385.  
  386.     BuildCodeReserve (kGZMaxAlloc, false);        // make sure code reserve is OK
  387.  
  388.     // reallocate the low space handle, if necessary
  389.     
  390.     if (IsHandlePurged (pMemReserve))
  391.     {
  392.         ReallocHandle (pMemReserve, pSzMemReserve);
  393. #if qDebug
  394.         theSize = GetHandleSize (pMemReserve);
  395. #pragma Push
  396. #pragma R-
  397.         if (theSize != 0)
  398.             BlockSet (*pMemReserve, theSize, initVal);
  399. #pragma Pop
  400. #endif
  401.     }
  402.  
  403.     pPermAllocation = oldPerm;            // reset the permanent flag 
  404. }
  405. #pragma Pop
  406.  
  407. /*--------------------------------------------------------------------------------------------------*/
  408. #pragma segment MAMemoryRes
  409. #pragma Push
  410. #if qTrace
  411. #pragma D+
  412. #endif
  413.  
  414. pascal void BuildCodeReserve(Size allocLim, Boolean fromGZ)
  415. {
  416.     static const short initVal = 0xF7;
  417.     
  418.     Size    needed, avail;
  419.     Handle    canPurge = 0;
  420. #if qDebug
  421.     Size    theSize;
  422. #endif
  423.     
  424.     pOKCodeReserve = true;                // default value 
  425.  
  426. #if qDebug
  427.     pReserveShortfall = 0;
  428.  
  429.     if (!pPermAllocation)
  430.         ProgramBreak ("BuildCodeReserve called with pPermAllocation = FALSE");
  431. #endif
  432.  
  433.     if (!pReserveExists)
  434.     {
  435.         pReserveExists = true;             // default value 
  436.  
  437.         // free the current code reserve 
  438.         if (IsHandleEligible (pCodeReserve))
  439.             EmptyHandle (pCodeReserve);
  440.  
  441.         // compute amt actually needed 
  442.         needed = Min (pSzCodeReserve - TotalTempSize (FALSE, canPurge) - 8, allocLim);
  443.  
  444.         if (needed > 0)
  445.         {
  446.             // make as much memory available as possible 
  447.             if (IsHandleEligible (pMemReserve))
  448.                 EmptyHandle (pMemReserve);
  449.  
  450.             if (fromGZ)                                // Never purge or compact from GrowZone 
  451.                 avail = allocLim;
  452.             else
  453.             {
  454.                 PurgeMem (needed);
  455.                 avail = CompactMem (needed);
  456.             }
  457.  
  458.             if (avail < needed)                        // could not get the whole reserve 
  459.             {
  460. #if qDebug
  461.                 pReserveShortfall = needed - avail;
  462. #endif
  463.                 pOKCodeReserve = false;
  464.                 pReserveExists = false;
  465.  
  466.                 needed = avail;                        // get the most we can 
  467.             }
  468.  
  469.             if (!fromGZ && (IsHandlePurged (pCodeReserve) || IsHandleEligible (pCodeReserve)))
  470.                 ReallocHandle (pCodeReserve, needed);
  471. #if qDebug
  472.             theSize = GetHandleSize (pCodeReserve);
  473. #pragma Push
  474. #pragma R-
  475.             if (theSize != 0)
  476.                 BlockSet (*pCodeReserve, theSize, initVal);
  477. #pragma Pop
  478. #endif
  479.             if (!IsHandlePurged (pCodeReserve))
  480.             {
  481.                 /* Large handles are almost as bad as nonrelocatable blocks.
  482.                 Try to get this guy out of the way, just in case.*/
  483.                 
  484.                 if (!fromGZ)
  485.                     MoveHHi (pCodeReserve);
  486.             }
  487.         }
  488.     }
  489. }
  490. /*$Pop*/
  491.  
  492. /*--------------------------------------------------------------------------------------------------*/
  493. #pragma segment MAMemoryRes
  494.  
  495. pascal Boolean CheckReserve ()
  496. {
  497.     BuildAllReserves ();
  498.     return pOKCodeReserve;
  499. }
  500.  
  501. /*--------------------------------------------------------------------------------------------------*/
  502. #if qDebug
  503. #pragma segment MAMemoryRes
  504.  
  505. pascal void CheckRsrcUsage ()
  506. {
  507.     long    sz;
  508.     Handle    h;
  509.     Str255    s;
  510.  
  511.     sz = TotalTempSize (true, h);
  512.     if (sz > gMaxLockedRsrc)
  513.     {
  514.         gMaxLockedRsrc = sz;
  515.         if (gRsrcReport)
  516.         {
  517.             NumToString (gMaxLockedRsrc, s);
  518.             s = "  = New maximum resources usage: " + s + " =";
  519.             ProgramReport (s, gMemMgtBreak);
  520.         }
  521.     }
  522. }
  523. #endif
  524.  
  525. /*--------------------------------------------------------------------------------------------------*/
  526. #if qDebug
  527. #pragma segment MADebug
  528.  
  529. pascal void DoChangeReserve (Boolean alter,
  530.                              Size& codeReserve, Size& codeShort, Size& lowSpaceReserve,
  531.                              Boolean& gotCode, Boolean& gotLowSpace)
  532. {
  533.     long    x;
  534.     Str255    s;
  535.     
  536.     if (alter)
  537.     {
  538.         cout << "code reserve size = " << pSzCodeReserve << "  ";
  539.         if (pOKCodeReserve)
  540.             cout << " (OK)\n";
  541.         else
  542.             cout << " (gone)\n";
  543.  
  544.         cout << "low space reserve size = " << pSzMemReserve << "  ";
  545.         if (!IsHandlePurged (pMemReserve))
  546.             cout << " (OK)\n";
  547.         else
  548.             cout << " (gone)\n";
  549.  
  550.         cout << "\n";
  551.  
  552.         cout << "New code reserve (-1 == no change): ";
  553.         cin >> x;
  554.         if (x >= 0)
  555.             codeReserve = x;
  556.         else
  557.             codeReserve = pSzCodeReserve;
  558.  
  559.         cout << "New low space reserve (-1 == no change): ";
  560.         cin >> x;
  561.         if (x >= 0)
  562.             lowSpaceReserve = x;
  563.         else
  564.             lowSpaceReserve = pSzMemReserve;
  565.  
  566.         cout << "Reset max resource usage (Y or N) [N]? ";
  567.         cin >> s;
  568.         if (s != "")
  569.         {
  570.             if ((s[1] == 'y') || (s[1] == 'Y'))
  571.                 gMaxLockedRsrc = 0;
  572.         }
  573.  
  574.         cout << "\n";
  575.  
  576.         SetReserveSize (codeReserve, lowSpaceReserve);
  577.     }
  578.     else
  579.         BuildAllReserves ();
  580.  
  581.     codeReserve = pSzCodeReserve;
  582.     codeShort = pReserveShortfall;
  583.     lowSpaceReserve = pSzMemReserve;
  584.     gotCode = pOKCodeReserve;
  585.     gotLowSpace = !IsHandlePurged (pMemReserve);
  586. }
  587. #endif
  588.  
  589. /*--------------------------------------------------------------------------------------------------*/
  590. #pragma segment MAMiniInit
  591.  
  592. /* Called from InitUMemory so that InitUMemory can be in the main segment
  593. and this code can be in another (unloadable) segment. */
  594.  
  595. pascal void DoInitUMemory (Size& sizeTempReserve, Size sizeLowSpaceReserve)
  596. {
  597.     struct Mem { long codeVal, lowSpaceVal, stackVal; };
  598.     typedef Mem *MemPtr, **MemHandle;
  599.  
  600.     short        i, rsrcCnt;
  601.     Boolean        oldResLoad;
  602.     Handle        seg, h;
  603.     long        StackTot;
  604.     short        rsrcID;
  605.     ResType        rsrcType;
  606.     Str255        rsrcName;
  607.     short        lastRsrc;
  608.     short        mainSegment, utilitySegment;
  609.  
  610.     // Initialize memory management globals
  611.     
  612.     pPermAllocation = false;
  613.     pMemReserve = NewHandle (0);
  614.     FailNIL (pMemReserve);
  615.  
  616.     pSzMemReserve = 0;
  617.     pCodeReserve = NewHandle (0);
  618.     FailNIL (pCodeReserve);
  619.  
  620.     pSzCodeReserve = 0;
  621.     gGZPurgeNotify = NULL;
  622.     pOKCodeReserve = true;
  623.     pReserveExists = false;
  624.  
  625.     gUnloadAllSegs = true;
  626.  
  627.     gCodeRefNum = HomeResFile (GetResource (kCode, 1));    /* Get homeresfile of "Main". It better be
  628.                                                          there!!*/
  629.     pMaxSegNum = 0;
  630.  
  631.     //###########################################
  632.     // No resource loading 
  633.  
  634.     oldResLoad = GetResLoad ();
  635.     SetResLoad (false);
  636.  
  637.     // Figure the highest segment number 
  638.     lastRsrc = MACount1Resources (kCode);
  639.  
  640.     /* some development systems may not have contiguous numbering of CODE segments.
  641.     try to be polite about handling it */
  642.     
  643.     for (i=1; i<= lastRsrc; i++)
  644.     {
  645.         seg = MAGet1IndResource (kCode, i);
  646.  
  647.         /* we only have an index… find the real resource ID and keep track
  648.         of the highest one */
  649.         
  650.         if (seg != NULL)
  651.         {
  652.             GetResInfo (seg, rsrcID, rsrcType, rsrcName);
  653.             pMaxSegNum =  (short) Max (rsrcID, pMaxSegNum);
  654.         }
  655.     }
  656.  
  657.     SetResLoad (oldResLoad);                             // in case of failure 
  658.  
  659.     // Allocate the master segment lists.
  660.     gCodeSegs = (HandleListHandle) NewHandle (pMaxSegNum * sizeof (Handle));
  661.     FailNIL (gCodeSegs);
  662.  
  663.     gIsResidentSeg = (BoolListHandle) NewHandle (sizeof (Boolean) * pMaxSegNum);
  664.     FailNIL (gIsResidentSeg);
  665.  
  666.     gIsLoadedSeg = (BoolListHandle) NewHandle (sizeof (Boolean) * pMaxSegNum);
  667.     FailNIL (gIsLoadedSeg);
  668.  
  669.     /* (NOTE: assumes application doesn't change the CODE segment size at runtime
  670.     (a very safe assumption)). Used in GetSegFromPC. */
  671.     
  672.     pSegSize = (LongListHandle) NewHandle (sizeof (long) * pMaxSegNum);
  673.     FailNIL (pSegSize);
  674.  
  675.     oldResLoad = GetResLoad ();                            // OK, suppress segment loading again 
  676.     SetResLoad (false);                                    /* !!! Need an MAResLoad that returns old
  677.                                                          state */
  678.  
  679.     // Initialize segment lists.
  680.     
  681.     for (i=1; i<=pMaxSegNum; i++)
  682.         (*gIsResidentSeg)[i] = false;
  683.  
  684.     // Segments and their sizes and actual loaded state (helps catch preloads)
  685.     
  686.     for (i=1; i<=pMaxSegNum; i++)
  687.     {
  688.         seg = GetSegResource (i);
  689.         (*gCodeSegs)[i] = seg;
  690.         if (seg != NULL)                                // seg is non-nil if the segment number
  691.         {
  692.             (*pSegSize)[i] = SizeResource (seg);
  693.             (*gIsLoadedSeg)[i] = IsHandleLocked (seg);
  694.         }
  695.         else
  696.         {
  697.             (*pSegSize)[i] = 0;
  698.             (*gIsLoadedSeg)[i] = false;
  699.         }
  700.     }
  701.  
  702.     SetResLoad(oldResLoad);
  703.     //###########################################
  704.  
  705.     mainSegment = GetSegNumber ((ProcPtr) &InitUMemory);            // Main is always resident 
  706.     (*gIsResidentSeg)[mainSegment] = true;
  707.     (*gIsLoadedSeg)[mainSegment] = true;
  708.  
  709.     utilitySegment = GetSegNumber ((ProcPtr) &UnloadAllSegments);    // Utilities are always resident 
  710.     (*gIsResidentSeg)[utilitySegment] = true;
  711.     (*gIsLoadedSeg)[utilitySegment] = true;
  712.  
  713.     // init the gSysMemList 
  714.     
  715.     gSysMemList = HandleListHandle (NewHandle (0));
  716.     FailNIL (gSysMemList);
  717.  
  718.     AddAllRsrc ('LDEF', gSysMemList);
  719.     AddAllRsrc ('CDEF', gSysMemList);
  720.     AddAllRsrc ('MDEF', gSysMemList);
  721.     AddAllRsrc ('WDEF', gSysMemList);
  722.     AddAllRsrc ('PACK', gSysMemList);
  723.  
  724.     // Compute memory slop needed
  725.     
  726.     sizeTempReserve = 0;
  727.     sizeLowSpaceReserve = 0;
  728.     StackTot = 0;
  729.  
  730.     rsrcCnt = CountResources ('seg!');
  731.     for (i=1; i<rsrcCnt; i++)
  732.     {
  733.         h = GetIndResource ('seg!', i);
  734.         sizeTempReserve += AddSegSizes (h);
  735.         ReleaseResource (h);
  736.     }
  737.  
  738.     rsrcCnt = CountResources ('mem!');
  739.     for (i=1; i<rsrcCnt; i++)
  740.     {
  741.         h = GetIndResource ('mem!', i);
  742.         {
  743.             const Mem& memH = **((MemHandle) h);
  744.             
  745.             sizeTempReserve += memH.codeVal;
  746.             sizeLowSpaceReserve += memH.lowSpaceVal;
  747.             StackTot += memH.stackVal;
  748.         }
  749.         ReleaseResource (h);
  750.     }
  751.  
  752.     SetStackSpace (StackTot);
  753.  
  754.     MaxApplZone ();
  755.  
  756.     gApp1MemList = NULL;
  757.     gApp2MemList = NULL;
  758. }
  759.  
  760. /*--------------------------------------------------------------------------------------------------*/
  761. #pragma segment MAMemoryRes
  762.  
  763. pascal void FailNoReserve ()
  764. {
  765.     if (!CheckReserve ())
  766.         Failure (memFullErr, 0);
  767. }
  768.  
  769. /*--------------------------------------------------------------------------------------------------*/
  770. #pragma segment MAMemoryRes
  771.  
  772. pascal void FailSpaceIsLow ()
  773. {
  774. #if qDebug
  775.     MAName    s;
  776.  
  777.     if (gAskFailure && CanReadLn ())
  778.     {
  779.         GetCallersMethodName (s);
  780.         if (ReadYesNo ("FailSpaceIsLow called by " + s + ".  Return true(Y or N) [N]? "))
  781.             Failure (memFullErr, 0);
  782.     }
  783. #endif
  784.  
  785.     if (MemSpaceIsLow ())
  786.         Failure (memFullErr, 0);
  787. }
  788.  
  789. /*--------------------------------------------------------------------------------------------------*/
  790. #pragma Push
  791. #if qTrace
  792. #pragma D+
  793. #endif
  794. #pragma segment MAMemoryRes
  795.  
  796. pascal void GetReserveSize (Size& szCodeReserve, Size& szMemReserve)
  797. {
  798.     szCodeReserve = pSzCodeReserve;
  799.     szMemReserve = pSzMemReserve;
  800. }
  801. #pragma Pop
  802.  
  803. /*--------------------------------------------------------------------------------------------------*/
  804. #pragma Push
  805. #if qTrace
  806. #pragma D+
  807. #endif
  808.                                                         /* no %_BP/%_EP allowed in here, because we
  809.                                                          cannot call to any other segment from this
  810.                                                          procedure */
  811. #pragma segment MAMemoryRes                                // Shouldn't be unloaded 
  812.  
  813. pascal short GetSegFromPC (long ppc)
  814. {
  815.     long        pc, segStart;
  816.     short        i;
  817.     Handle        seg;
  818.     
  819.     pc = *((LongIntPtr) ppc);
  820.  
  821.     /* Since GetSegFromPC may be called before gCodeSegs is set up, we have to test if gCodeSegs == NULL
  822.     before using it. */
  823.     
  824.     if (gCodeSegs != NULL)
  825.         for (i=1; i<=pMaxSegNum; i++)
  826.         {
  827.             seg = (*gCodeSegs)[i];                        // get segment handle 
  828.             if ((seg != NULL) && !IsHandlePurged (seg))     // it's in memory 
  829.             {
  830.                 segStart = StripLong(*seg);                // get segment start 
  831.                 if ((pc >= segStart) && (pc < segStart + (*pSegSize)[i]))
  832.                     return i;
  833.             }
  834.         }
  835.     
  836.     return 0;            // default return
  837. }
  838. #pragma Pop
  839.  
  840. /*--------------------------------------------------------------------------------------------------*/
  841. #pragma Push
  842. #if qTrace
  843. #pragma D+
  844. #endif
  845.                                                         /* no %_BP/%_EP allowed in here, because we
  846.                                                          cannot call to any other segment from this
  847.                                                          procedure */
  848.                                                          
  849. #pragma segment MAMemoryRes                                /* must be in Main segment because we call
  850.                                                          this in order to make the resident segment
  851.                                                          resident */
  852.  
  853. pascal short GetSegNumber (ProcPtr aProc)
  854.     /* Gets seg number from a Jump table address */
  855. {
  856.     static const short kLoaded = 0x4EF9;        // if loaded then a JMP instruction 
  857.     static const short kUnLoaded = 0x3F3C;        // if unloaded then a LoadSeg trap
  858.     
  859.     if (*((IntegerPtr) aProc) == kLoaded)                // loaded segment 
  860.         return *((IntegerPtr) ((Ptr) aProc - 2));
  861.     else if ((*IntegerPtr(aProc)) == kUnLoaded)         // unloaded segment 
  862.         return *((IntegerPtr) ((Ptr) aProc + 2));
  863.     else                                                /* routine that computed &proc was in same
  864.                                                          segment as the proc */
  865.     {
  866. #if qDebug
  867.         ProgramBreak("GetSegNumber was not passed an jump table address");
  868. #endif
  869.         return 0;
  870.     }
  871. }
  872. #pragma Pop
  873.  
  874. /*--------------------------------------------------------------------------------------------------*/
  875. #pragma segment MAMemoryRes
  876. #pragma Push
  877. #if qTrace
  878. #pragma D+
  879. #endif
  880.  
  881. pascal Size GetSegSize (short segNum)
  882. {
  883.     return (*pSegSize)[segNum];
  884. }
  885. #pragma Pop
  886.  
  887. /*--------------------------------------------------------------------------------------------------*/
  888. #pragma segment MAMemoryRes
  889. #pragma Push
  890. #if qTrace
  891. #pragma D+
  892. #endif
  893.  
  894. pascal long GrowZoneProc (Size)
  895. {
  896.     long        result, reserveSize, OldA5;
  897.     Handle        canPurge;
  898.     Size        codeSize;
  899.     
  900.     OldA5 = SetCurrentA5 ();                        // Can be called from other worlds 
  901.  
  902.     result = 0;                                        // default is to fail 
  903.  
  904.     if (!pDuringGrowZone)                             // prevent re-entrancy 
  905.     {
  906.         pDuringGrowZone = true;
  907.         
  908.         // on a temp alloc, free all code slack immediately 
  909.         
  910.         if (!pPermAllocation && IsHandleEligible (pCodeReserve))
  911.         {
  912.             EmptyHandle (pCodeReserve);
  913.             pReserveExists = false;
  914.             result = 1;
  915.         }
  916.  
  917.         if (result == 0)                                /* try harder: see if we can purge a code
  918.                                                          segment or reduce the code reserve handle
  919.                                                          */
  920.         {
  921.             // compute size of resources currently in memory 
  922.  
  923.             codeSize = TotalTempSize (false, canPurge);
  924.  
  925.             // see if the code reserve handle is too large 
  926.  
  927.             if (IsHandleEligible (pCodeReserve))
  928.                 /* we have a code reserve handle; this implies permanent allocation,
  929.                 otherwise the handle would have been emptied above */
  930.             {
  931.                 reserveSize = GetHandleSize (pCodeReserve);
  932.  
  933.                 /* the following test is an optimization to avoid calling
  934.                 BuildCodeReserve if there is no hope of reducing
  935.                 the code reserve handle */
  936.                 
  937.                 if (codeSize + reserveSize + 8 > pSzCodeReserve)
  938.                 {                                // reserve is too big 
  939.                     pReserveExists = false;
  940.                     // this should lower the code reserve 
  941.                     BuildCodeReserve (reserveSize, true);
  942.  
  943.                     // see if we succeeded in freeing some memory 
  944.                     if (IsHandlePurged (pCodeReserve))
  945.                         result = 1;
  946.                     else if (GetHandleSize (pCodeReserve) < reserveSize)
  947.                         result = 1;
  948.                 }
  949.             }
  950.  
  951.             if ((result == 0) && (canPurge != NULL) && (!pPermAllocation ||
  952.                IsHandlePurged (pCodeReserve)))               /* got something; only purge it if this is
  953.                                                          temporary || we know there is too much
  954.                                                          code in memory already */
  955.             {
  956.                 if (gGZPurgeNotify != NULL)
  957.                     CallNotify (canPurge, gGZPurgeNotify);
  958.  
  959.                 reserveSize = GetHandleSize (canPurge);
  960.                 HPurge (canPurge);
  961.                 EmptyHandle (canPurge);
  962.                 pReserveExists = false;
  963.  
  964.                 if (pPermAllocation)                 // don't free too much however 
  965.                     BuildCodeReserve (reserveSize, true);
  966.  
  967.                 result = 1;
  968.             }
  969.         }
  970.  
  971.         if ((result == 0) && IsHandleEligible (pMemReserve)) /* last ditch attempt-free emergency
  972.                                                               reserve*/
  973.         {
  974.             EmptyHandle (pMemReserve);
  975.             result = 1;
  976.         }
  977.  
  978.         pDuringGrowZone = false;
  979.     }
  980.  
  981.     OldA5 = SetA5 (OldA5);
  982.     
  983.     return result;
  984. }
  985. #pragma Pop
  986.  
  987. /*--------------------------------------------------------------------------------------------------*/
  988. #pragma segment MAMemoryRes
  989. #pragma Push
  990. #if qTrace
  991. #pragma D+
  992. #endif
  993.  
  994. pascal Boolean IsHandleEligible (Handle h)
  995. {
  996.     if (h == NULL)
  997.         return false;                                // Thanks Pillar! 
  998.     else if (IsHandlePurged (h))
  999.         return false;
  1000.     else
  1001.         return (h != GetGZMoveHnd ()) && (h != GetGZRootHnd ());
  1002. }
  1003. #pragma Pop
  1004.  
  1005. /*--------------------------------------------------------------------------------------------------*/
  1006. #pragma segment MAMemoryRes                                        /* Must be in same segment as grow zone proc */
  1007. #pragma Push
  1008. #if qTrace
  1009. #pragma D+
  1010. #endif
  1011.  
  1012. pascal void InstallGrowZoneProc ()
  1013.     /* Once called the grow zone proc's segment CAN!be moved since we're passing a NON-JT address
  1014.     to SetGrowZone (so we can be called from "other worlds" */
  1015. {
  1016.     THz        aZone;
  1017.  
  1018.     pDuringGrowZone = false;
  1019.     aZone = ApplicZone ();
  1020.     aZone->flags |= 0x0400;
  1021.     
  1022.     /* set the Memory Manager bit that says to always call the
  1023.     Grow Zone proc, even in "non-critical" situations */
  1024.  
  1025.     SetGrowZone (&GrowZoneProc);
  1026. }
  1027. #pragma Pop
  1028.  
  1029. /*--------------------------------------------------------------------------------------------------*/
  1030. #pragma segment Main            /* Must be in main segment and called from main segment */
  1031.  
  1032. pascal void InitUMemory ()
  1033.     {
  1034.  
  1035.     Size    codeRes, lowSpaceRes = 0;
  1036.     Handle    miniInitSeg;
  1037.     
  1038.     /* Get these segments out of the way so that when DoInitUMemory gets called and the next
  1039.     block of master pointers gets allocated they won't constipate the heap */
  1040.     
  1041.     miniInitSeg = GetResource (kCode, GetSegNumber ((ProcPtr) &DoInitUMemory));
  1042.     if (miniInitSeg != NULL)
  1043.     {
  1044.         UnloadSeg (&DoInitUMemory);
  1045.         LockHandleHigh (miniInitSeg);
  1046.     }
  1047.  
  1048.     DoInitUMemory (codeRes, lowSpaceRes);
  1049.  
  1050.     UnloadAllSegments ();                                /* get init segment(s) out of middle of heap,
  1051.                                                          so SetReserveSize has maximum space to
  1052.                                                          work with */
  1053.  
  1054.     if (miniInitSeg != NULL)                            /* Yes, this would eventually get purged if
  1055.                                                          the space was needed badly enough, but
  1056.                                                          that happens very late in the game and can
  1057.                                                          confound the unwary */
  1058.     EmptyHandle (miniInitSeg);
  1059.  
  1060.     InstallGrowZoneProc ();
  1061.  
  1062.     SetReserveSize (codeRes, lowSpaceRes);
  1063.     if (!pOKCodeReserve)                                /* couldn't get code reserve. Can't continue */
  1064.         Failure(memFullErr, 0);
  1065.     else
  1066.     {
  1067.         // Set up the LoadSeg patch 
  1068.  
  1069.         //!!! needs fixing before final!!! 
  1070.         if (!qModelFar)
  1071.             FailOSErr (PatchTrap (pSegLoadPatch, _LoadSeg, (Ptr) &ALoadMacAppSeg));
  1072.     }
  1073. }
  1074.  
  1075. /*--------------------------------------------------------------------------------------------------*/
  1076. #pragma Push
  1077. #if qTrace
  1078. #pragma D+
  1079. #endif
  1080.                                                         /* no %_BP/%_EP allowed in here, because we
  1081.                                                          cannot call to any other segment from this
  1082.                                                          procedure */
  1083.                                                          
  1084. #pragma segment MAMemoryRes                                // must be in Main segment 
  1085.  
  1086. pascal long LoadMacAppSegment (short segNum)
  1087. {
  1088. #if qDebug
  1089.     short        id;
  1090.     ResType        kind;
  1091.     Str255        segName;
  1092.     MAName        s;
  1093.     Handle        seg;
  1094. #endif
  1095.     long        A5RegisterOnEntry;
  1096.     long        loadMacAppSegment;
  1097.  
  1098.     A5RegisterOnEntry = SetCurrentA5 ();                // ***** Called from trap patches *****
  1099.  
  1100.     loadMacAppSegment = pSegLoadPatch.oldTrapAddr;         // Where to go next 
  1101.  
  1102.     if (GetA5 () != A5RegisterOnEntry)
  1103.     {
  1104.         // not called from our application… don't do patch behaviour. Thank you McSink! 
  1105.         pLoadSegCalledFromOwnApp = false;
  1106.         if (SetA5 (A5RegisterOnEntry) != 0);
  1107.     }
  1108.     else
  1109.     {
  1110.         pLoadSegCalledFromOwnApp = true;
  1111.         pOldResFile = MAUseResFile (gCodeRefNum);        /* Must set a global because we return from
  1112.                                                          this function and then forward to the
  1113.                                                          actual segment loader which should also be
  1114.                                                          pointing to the _now_ correct resfile.
  1115.                                                          When we get called back again in
  1116.                                                          PostLoadMacAppSegment we will restore the
  1117.                                                          old resFile as the current resFile. Sorry
  1118.                                                          about the global. */
  1119.  
  1120. #if qDebug
  1121.         if (!GetResLoad ())
  1122.          {
  1123.             SetResLoad (true);
  1124.             ProgramBreak ("Whoops… LoadSeg called with resload set false");
  1125.             Failure (minErr, 0);                         /*??? Assign an error code someday or
  1126.                                                          setresload to true ???*/
  1127.          }
  1128.  
  1129. #endif
  1130.  
  1131.         if (!PreloadSegmentResource(segNum))
  1132.         {
  1133. #if qDebug
  1134.             GetCallersMethodName (s);
  1135.             SetResLoad (false);
  1136.             seg = MAGet1Resource (kCode, segNum);
  1137.  
  1138.             GetResInfo (seg, id, kind, segName);
  1139.             SetResLoad (true);
  1140.             ProgramBreak ("In " + s + form (" couldn''t load segment: %d", segNum) + segName);
  1141. #endif
  1142.             Failure (memFullErr, 0);
  1143.         }
  1144.  
  1145.         (*gIsLoadedSeg)[segNum] = true;
  1146.  
  1147. #if qDebug
  1148.         if (gSegReport)
  1149.         {
  1150.             // Cause the debugger to break at the start of the next routine. 
  1151.             gReportNext = true;
  1152.             GetResInfo ((*gCodeSegs)[segNum], id, kind, segName);
  1153.             gReportInfo = form ("  *** Segment Loaded: %d ", segNum) + segName;
  1154.             gSingleStep = gMemMgtBreak;
  1155.         }
  1156. #endif
  1157.  
  1158.     }
  1159.  
  1160.     return loadMacAppSegment;
  1161. }
  1162. #pragma Pop
  1163.  
  1164. /*--------------------------------------------------------------------------------------------------*/
  1165. #pragma Push
  1166. #if qTrace
  1167. #pragma D+
  1168. #endif
  1169.                                                         /* no %_BP/%_EP allowed in here, because we
  1170.                                                          cannot call to any other segment from this
  1171.                                                          procedure */
  1172. #pragma Z+
  1173. #pragma segment MAMemoryRes                                // must be in Main segment 
  1174.  
  1175. pascal void PostLoadMacAppSegment ()
  1176. {
  1177.     long    A5RegisterOnEntry;
  1178.  
  1179.     A5RegisterOnEntry = SetCurrentA5 ();                // ***** Called from trap patches *****
  1180.  
  1181.     if (GetA5 () != A5RegisterOnEntry || !pLoadSegCalledFromOwnApp)
  1182.     {
  1183.         // not called from our application… don't do patch behaviour. Thank you McSink! 
  1184.         SetA5 (A5RegisterOnEntry);
  1185.     }
  1186.     else
  1187.     {
  1188.         // Called back from our glue.  Restores current res file pointer. 
  1189.         if (pLoadSegCalledFromOwnApp)
  1190.             MAUseResFile (pOldResFile);
  1191.         SetA5 (A5RegisterOnEntry);
  1192.     }
  1193. }
  1194. #pragma Pop
  1195.  
  1196. /*--------------------------------------------------------------------------------------------------*/
  1197. #pragma segment MAMemoryRes                                        // Must be in Main segment 
  1198.  
  1199. pascal void LoadResidentSegments ()
  1200. {
  1201.     short            resIndex, i, offset, segNumber, rsrcCnt;
  1202.     Handle            nameList, seg;
  1203.     SignedBytePtr    p;
  1204.     Str255            name;
  1205.     ResType            theType;
  1206.     
  1207.     rsrcCnt = CountResources('res!');
  1208.     for (resIndex=1; resIndex<=rsrcCnt; resIndex++)
  1209.     {
  1210.         nameList = GetIndResource ('res!', resIndex);
  1211.         HNoPurge (nameList);
  1212.  
  1213.         offset = 2;
  1214.         for (i=1; i<=*((IntegerPtr) *nameList); i++)
  1215.         {
  1216.             p = (SignedBytePtr) *nameList + offset;
  1217.             BlockMove ((Ptr) p, (Ptr) &name, *p + 1);
  1218.             offset += name.Length () + 1;
  1219.  
  1220.             seg = MAGet1NamedResource (kCode, name);
  1221.  
  1222.             if (seg != NULL)
  1223.             {
  1224.                 GetResInfo (seg, segNumber, theType, name);
  1225.                 SetResidentSegment (segNumber, true);
  1226.             }
  1227.         }
  1228.  
  1229.         HPurge (nameList);
  1230.         ReleaseResource (nameList);
  1231.     }
  1232. }
  1233.  
  1234. /*--------------------------------------------------------------------------------------------------*/
  1235. #pragma segment MAMemoryRes
  1236.  
  1237. pascal Boolean MemSpaceIsLow ()
  1238. {
  1239.     BuildAllReserves ();
  1240.     return IsHandlePurged (pMemReserve);
  1241. }
  1242.  
  1243. /*--------------------------------------------------------------------------------------------------*/
  1244. #pragma segment MAMemoryRes
  1245.  
  1246. pascal Handle NewPermHandle (Size logicalSize)
  1247. {
  1248.     static const short initVal = 0xF3;            // odd at all byte boundaries            
  1249.  
  1250.     Boolean        priorPerm;
  1251.     Handle        aHandle;
  1252.     
  1253.     priorPerm = PermAllocation (true);
  1254.     aHandle = NewHandle (logicalSize);
  1255.     pPermAllocation = priorPerm;
  1256.     FailNIL (aHandle);
  1257. #pragma Push
  1258. #pragma R-
  1259.     if (qDebug)
  1260.         BlockSet (*aHandle, logicalSize, initVal);
  1261. #pragma Pop
  1262.     return aHandle;
  1263. }
  1264.  
  1265. /*--------------------------------------------------------------------------------------------------*/
  1266. #pragma segment MAMemoryRes
  1267.  
  1268. pascal Ptr NewPermPtr (Size logicalSize)
  1269. {
  1270.     static const short initVal = 0xF3;            // odd at all byte boundaries            
  1271.  
  1272.     Boolean        priorPerm;
  1273.     Ptr            aPtr;
  1274.  
  1275.     
  1276.     priorPerm = PermAllocation (true);
  1277.     aPtr = NewPtr (logicalSize);
  1278.     pPermAllocation = priorPerm;
  1279.     FailNIL (aPtr);
  1280. #pragma Push
  1281. #pragma R-
  1282.     if (qDebug)
  1283.         BlockSet(aPtr, logicalSize, initVal);
  1284. #pragma Pop
  1285.     return aPtr;
  1286. }
  1287.  
  1288. /*--------------------------------------------------------------------------------------------------*/
  1289. #pragma Push
  1290. #if qTrace
  1291. #pragma D+
  1292. #endif
  1293. #pragma segment MAMemoryRes
  1294.  
  1295. pascal Boolean PermAllocation (Boolean permanent)
  1296. {
  1297.     Boolean permAllocation = pPermAllocation;
  1298.     
  1299.     if (permanent != pPermAllocation)
  1300.     {
  1301.         pPermAllocation = permanent;
  1302.         if (permanent)
  1303.             BuildCodeReserve (kGZMaxAlloc, false);
  1304.     }
  1305.     
  1306.     return permAllocation;
  1307. }
  1308. #pragma Pop
  1309.  
  1310. /*--------------------------------------------------------------------------------------------------*/
  1311. #pragma Push
  1312. #if qTrace
  1313. #pragma D+
  1314. #endif
  1315.                                                         /* no %_BP/%_EP allowed in here, because we
  1316.                                                          cannot call to any other segment from this
  1317.                                                          procedure */
  1318. #pragma segment MAMemoryRes                                // must be in Main segment 
  1319.  
  1320. class LWithCodeResFileDo {
  1321.     short& fSegNum;
  1322.     Handle& fSeg;
  1323. public:
  1324.     LWithCodeResFileDo (short& segNum, Handle& seg) : fSegNum (segNum), fSeg (seg) { }
  1325.     pascal void DoGetSegHandle ()
  1326.         { fSeg = Get1Resource (kCode, fSegNum); }
  1327. };
  1328.     
  1329. pascal Boolean PreloadSegmentResource (short segNum)
  1330. {
  1331.     Handle        seg;
  1332.     LWithCodeResFileDo scopeLink (segNum, seg);
  1333.  
  1334.     if (qDebug && pPermAllocation)
  1335.     {
  1336.         cout << "segment # = " << segNum;
  1337.         ProgramBreak ("Trying to load a segment with PermAllocation == true.");
  1338.     }
  1339.  
  1340.     WithCodeResFileDo ((DoWithResFileType) &LWithCodeResFileDo::DoGetSegHandle, &scopeLink);
  1341.  
  1342.     if (seg == NULL)
  1343.         return false;
  1344.     else
  1345.     {
  1346.         if (!IsHandleLocked (seg))                 // not yet locked 
  1347.             LockHandleHigh (seg);
  1348.         return true;
  1349.     }
  1350. }
  1351. #pragma Pop
  1352.  
  1353. /*--------------------------------------------------------------------------------------------------*/
  1354. #pragma segment MAMemoryRes
  1355.  
  1356. pascal void RemHandle (Handle h, HandleListHandle toList)
  1357. {
  1358.     long    p, maxP, offset;
  1359.     
  1360.     p = (long) *toList;                                    // Address of first element 
  1361.     maxP = p + GetHandleSize ((Handle) toList);            // Address past last element 
  1362.  
  1363.     // Skip elements until item is found 
  1364.     while ((p < maxP) && *((LongIntPtr) p) != (long) h)
  1365.         p += sizeof (Handle);
  1366.  
  1367.     if (p < maxP)                                    // Item was found 
  1368.     {
  1369.         offset = Munger ((Handle) toList, p - (long) *toList,
  1370.                           NULL, sizeof (Handle), (Ptr) &h, 0);
  1371.         FailMemError ();
  1372.     }
  1373. }
  1374.  
  1375. /*--------------------------------------------------------------------------------------------------*/
  1376. #pragma segment MAMemoryRes
  1377. #pragma Push
  1378. #if qTrace
  1379. #pragma D+
  1380. #endif
  1381.  
  1382. typedef Handle *HandlePtr;
  1383.  
  1384. pascal void ScanList (HandleListHandle list, DoToHandlesType DoToHandle, void *)
  1385. {
  1386.     short        i = (short) (GetHandleSize ((Handle) list) / sizeof (Handle));
  1387.     HandlePtr    p = (HandlePtr) *list;
  1388.     
  1389.     for (; i>0; i--, p++)
  1390.         DoToHandle (*p, NULL);
  1391. }
  1392.  
  1393. pascal void ScanHandles (DoToHandlesType DoToHandle, void *)
  1394. {
  1395.     ScanList (gCodeSegs, DoToHandle, NULL);
  1396.     if (gApp1MemList != NULL)
  1397.         ScanList (gApp1MemList, DoToHandle, NULL);
  1398.     ScanList (gSysMemList, DoToHandle, NULL);
  1399.     if (gApp2MemList != NULL)
  1400.         ScanList (gApp2MemList, DoToHandle, NULL);
  1401. }
  1402. #pragma Pop
  1403.  
  1404. /*--------------------------------------------------------------------------------------------------*/
  1405. #pragma segment MAMemoryRes
  1406.  
  1407. pascal void SetPermHandleSize (Handle h, Size newSize)
  1408. {
  1409.     static const short initVal = 0xF3;
  1410.     
  1411.     Boolean    priorPerm;
  1412. #if qDebug
  1413.     Size    oldSize;
  1414. #endif
  1415.  
  1416.     priorPerm = PermAllocation (true);
  1417. #if qDebug
  1418.     oldSize = GetHandleSize (h);
  1419. #endif
  1420.     SetHandleSize (h, newSize);
  1421.     pPermAllocation = priorPerm;                        /* Since we are in the memory unit we can
  1422.                                                          break the encapsulation of the
  1423.                                                          PermAllocation Call to just set the
  1424.                                                          pPermAllocation flag back directly. This
  1425.                                                          lets us be assured that no operations have
  1426.                                                          occurred that would invalidate the MemErr
  1427.                                                          flag… thus the following call will give a
  1428.                                                          true result*/
  1429.     FailMemError ();
  1430. #if qDebug
  1431. #pragma Push
  1432. #pragma R-
  1433.     if (oldSize < newSize)
  1434.         BlockSet ((Ptr) *h + oldSize, newSize - oldSize, initVal);
  1435. #pragma Pop
  1436. #endif
  1437. }
  1438.  
  1439. /*--------------------------------------------------------------------------------------------------*/
  1440. #pragma segment MAMemoryRes
  1441.  
  1442. pascal void SetPermPtrSize (Ptr p, Size newSize)
  1443. {
  1444.     static const short initVal = 0xF5;
  1445.     
  1446.     Boolean    priorPerm;
  1447. #if qDebug
  1448.     Size    oldSize;
  1449. #endif
  1450.  
  1451.     priorPerm = PermAllocation (true);
  1452. #if qDebug
  1453.     oldSize = GetPtrSize (p);
  1454. #endif
  1455.     SetPtrSize (p, newSize);
  1456.     pPermAllocation = priorPerm;                        /* Since we are in the memory unit we can
  1457.                                                          break the encapsulation of the
  1458.                                                          PermAllocation Call to just set the
  1459.                                                          pPermAllocation flag back directly. This
  1460.                                                          lets us be assured that no operations have
  1461.                                                          occurred that would invalidate the MemErr
  1462.                                                          flag… thus the following call will give a
  1463.                                                          true result*/
  1464.     FailMemError ();
  1465. #if qDebug
  1466. #pragma Push
  1467. #pragma R-
  1468.     if (oldSize < newSize)
  1469.         BlockSet ((Ptr) p + oldSize, newSize - oldSize, initVal);
  1470. #pragma Pop
  1471. #endif
  1472. }
  1473.  
  1474. /*--------------------------------------------------------------------------------------------------*/
  1475. #pragma segment MAMemoryRes
  1476.  
  1477. pascal void SetReserveSize (Size forCode, Size forOther)
  1478. {
  1479.     pSzCodeReserve = forCode;
  1480.     pSzMemReserve = forOther;
  1481.  
  1482.     // Since the numbers have changed, make sure we start from scratch. 
  1483.     pReserveExists = false;
  1484.     EmptyHandle (pMemReserve);
  1485.  
  1486.     BuildAllReserves ();
  1487. }
  1488.  
  1489. /*--------------------------------------------------------------------------------------------------*/
  1490. #pragma Push
  1491. #if qTrace
  1492. #pragma D+
  1493. #endif
  1494.                                                         /* no %_BP/%_EP allowed in here, because we
  1495.                                                          cannot call to any other segment from this
  1496.                                                          procedure */
  1497. #pragma segment MAMemoryRes                                // must be in Main segment 
  1498.  
  1499. pascal void SetResidentSegment(short segNum, Boolean makeResident)
  1500. {
  1501. #if qDebug
  1502.         short    id;
  1503.         ResType    kind;
  1504.         Str255    segName;
  1505.         MAName    s;
  1506.         Handle    seg;
  1507. #endif
  1508.  
  1509.     //!!! needs fixing before final!!! 
  1510.     if (qModelFar)
  1511.         return;
  1512.  
  1513.     if (makeResident)
  1514.     {
  1515.         (*gIsResidentSeg)[segNum] = true;
  1516.         if (!PreloadSegment (segNum))
  1517.         {
  1518. #if qDebug
  1519.             GetCallersMethodName (s);
  1520.             SetResLoad (false);
  1521.             seg = MAGet1Resource (kCode, segNum);
  1522.             SetResLoad (true);
  1523.             GetResInfo (seg, id, kind, segName);
  1524.             ProgramBreak ("In " + s + form (" couldn''t load segment: %d", segNum) + segName);
  1525. #endif
  1526.             Failure (memFullErr, 0);
  1527.         }
  1528.     }
  1529.     else
  1530.         (*gIsResidentSeg)[segNum] = false;
  1531. }
  1532. #pragma Pop
  1533.  
  1534. /*--------------------------------------------------------------------------------------------------*/
  1535. #pragma segment MAMiniInit
  1536.  
  1537. pascal void SetStackSpace (long numBytes)
  1538. {
  1539.     long    newLimit;
  1540.     
  1541.     newLimit = (long) GetCurStackBase () - numBytes;
  1542.     if ((long) GetApplLimit () > newLimit)
  1543.         SetApplLimit ((Ptr) newLimit);
  1544. }
  1545.  
  1546. /*--------------------------------------------------------------------------------------------------*/
  1547. #pragma segment MAMemoryRes
  1548. #pragma Push
  1549. #if qTrace
  1550. #pragma D+
  1551. #endif
  1552.  
  1553. class LTotalTempSize {
  1554.     Boolean& fJustLocked;
  1555.     Handle& fCanPurge;
  1556.     Size& fTotal;
  1557.     THz& fApplZone;
  1558. public:
  1559.     LTotalTempSize (Boolean& justLocked, Handle& canPurge, Size& total, THz& applZone)
  1560.         : fJustLocked (justLocked), fCanPurge (canPurge), fTotal (total), fApplZone (applZone) { }
  1561.  
  1562.     pascal void TotalUp(Handle h)
  1563.     {
  1564.         Boolean        hIsLocked;
  1565.         
  1566.         if (!IsHandlePurged (h))                    // in memory already 
  1567.             if (HandleZone (h) == fApplZone)        // in application heap 
  1568.             {
  1569.                 HNoPurge (h);
  1570.  
  1571.                 hIsLocked = IsHandleLocked (h);
  1572.  
  1573.                 if (!fJustLocked || hIsLocked)
  1574.                     fTotal += GetHandleSize (h) + 8;
  1575.                 // add in the size plus heap overhead 
  1576.  
  1577.                 if (!hIsLocked)
  1578.                     if (fCanPurge == NULL)
  1579.                         if (IsHandleEligible (h))
  1580.                             fCanPurge = h;
  1581.             }
  1582.     }
  1583. };
  1584.  
  1585. pascal Size TotalTempSize (Boolean justLocked, Handle& canPurge)
  1586. {
  1587.     Size    total;
  1588.     THz        applZone;
  1589.     LTotalTempSize scopeLink (justLocked, canPurge, total, applZone);
  1590.  
  1591.     canPurge = NULL;
  1592.     total = 0;
  1593.     applZone = ApplicZone ();
  1594.  
  1595.     ScanHandles ((DoToHandlesType) <otalTempSize::TotalUp, &scopeLink);
  1596.  
  1597.     return total;
  1598. }
  1599. #pragma Pop
  1600.  
  1601. /*--------------------------------------------------------------------------------------------------*/
  1602. #pragma segment MAMemoryRes
  1603. #pragma Push
  1604. #if qTrace
  1605. #pragma D+
  1606. #endif
  1607.  
  1608. pascal void WithCodeResFileDo (pascal void (*DoWithResFile) (void* scopeLink), void* scopeLink)
  1609. {
  1610.     short    oldResFile;
  1611.     
  1612.     oldResFile = MAUseResFile (gCodeRefNum);
  1613.     DoWithResFile (scopeLink);
  1614.     MAUseResFile (oldResFile);
  1615. }
  1616. #pragma Pop
  1617.  
  1618. /*--------------------------------------------------------------------------------------------------*/
  1619. #pragma Push
  1620. #if qTrace
  1621. #pragma D+
  1622. #endif
  1623.                                                         /* no %_BP/%_EP allowed in here, because we
  1624.                                                          cannot call to any other segment from this
  1625.                                                          procedure */
  1626. #pragma segment MAMemoryRes                                // must be in Main segment 
  1627.  
  1628. class LUnloadAllSegments {
  1629.     Handle& seg;
  1630.     long& jmpTablePtr;
  1631. public:
  1632.     LUnloadAllSegments (Handle& aSeg, long& aJmpTablePtr)
  1633.         : seg (aSeg), jmpTablePtr (aJmpTablePtr) { }
  1634.         
  1635.     pascal void DoToFrame (long, long ppc,
  1636.                            long, long)
  1637.     {
  1638.         short        seg;
  1639.         
  1640.         seg = GetSegFromPC (ppc);
  1641.         if ((seg != 0) && !((*gIsResidentSeg)[seg] && (*gIsLoadedSeg)[seg]))
  1642.         {
  1643.             cout << "Segment#: " << seg;
  1644.             ProgramBreak("I really don''t think that you want to unload a segment into which you are going to return!");
  1645.         }
  1646.     }
  1647.  
  1648.     pascal void UnloadEm ()
  1649.     {
  1650.         short    i;
  1651.  
  1652.         for (i=1; i<=pMaxSegNum; i++)
  1653.         {
  1654.             if (!(*gIsResidentSeg)[i] && (*gIsLoadedSeg)[i])
  1655.             {
  1656.                 seg = (*gCodeSegs)[i];
  1657.                 if ((seg != NULL) && !IsHandlePurged (seg))
  1658.                 {
  1659.                     UnloadSeg ((Ptr) jmpTablePtr + **((IntegerHandle) seg) + 2);
  1660.                     (*gIsLoadedSeg)[i] = false;
  1661.                 }
  1662.             }
  1663.         }
  1664.     }
  1665. };
  1666.         
  1667. pascal void UnloadAllSegments (void)
  1668. {
  1669.     long        jumpTablePtr;
  1670.     Handle        seg;
  1671.  
  1672.     //!!! needs fixing before final!!! 
  1673.     if (qModelFar)
  1674.         return;
  1675.  
  1676. #if qDebug
  1677.     CheckRsrcUsage ();
  1678. #endif
  1679.  
  1680.     if (gUnloadAllSegs)
  1681.     {
  1682.         jumpTablePtr = (long ) GetA5 () + GetCurJTOffset ();
  1683.  
  1684.         LUnloadAllSegments localScope (seg, jumpTablePtr);
  1685. #if qDebug
  1686.         EachFrameDo ((long) GetCurStackFramePtr (),
  1687.                      (long) GetCurStackFramePtr () + 4,
  1688.                      (DoToFrameType) &LUnloadAllSegments::DoToFrame, &localScope);
  1689. #endif
  1690.  
  1691.         WithCodeResFileDo ((DoWithResFileType) &LUnloadAllSegments::UnloadEm, &localScope);
  1692.  
  1693.         if (gSegReport)
  1694.             ProgramReport ("  *** Just unloaded all segments ***", gMemMgtBreak);
  1695.     }
  1696. }
  1697. #pragma Pop
  1698.  
  1699. /*--------------------------------------------------------------------------------------------------*/
  1700. #if qDebug
  1701. #pragma segment MADebug
  1702.  
  1703. pascal void WriteReserves ()
  1704. /* WRITELN's the temporary reserve and low-memory reserves in the
  1705. debug window. */
  1706.  
  1707. {
  1708.     WrLblPtr ("Temporary reserve (pCodeReserve)", (long) pCodeReserve);
  1709.     cout << "\n";
  1710.     WrLblPtr ("Low-memory reserve (pMemReserve)", (long) pMemReserve);
  1711.     cout << "\n";
  1712. }
  1713. #endif
  1714.